//=========学生类型的数据结构======
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

//test
//#include <unistd.h>

#include "slinklist.h"

/*
//链表节点定义
typedef struct sNode
{
	int id;			//学号(遍历) 8位数
	char password[20];//密码(遍历) 20位数
	char name[30];	//姓名(三个char类型存放一个中文字符) 3*10
	char sex[5]; 	//性别
	char idcard[19];//身份证18+1 
	char phone[12];	//手机号11+1
	char state;//学生状态 0:在读 1:退学

	float ChineseScore;
	float MathScore;
	float EnglishScore;

	float TotalScore;	//三科的总分
	int ScoreRank;	//总分的排名

	struct sNode *prev;
	struct sNode *next;
}sNode;
//链表定义
typedef struct
{
	struct sNode *head;
	struct sNode *tail;
}*sLink;
//分数结果
typedef struct
{
	float CHScore,MHScore,EHScore;	//单科最高分
	double CScore,MScore,EScore; 	//单科总分
	float CAScore,MAScore,EAScore; 	//单科平均分
}*sResult;
*/

//创建链表
sLink Create_sLink()
{
	sLink SL = (sLink)malloc(sizeof(sLink));
	SL->head = NULL;
	SL->tail = NULL;
	return SL;
}
//工号查找,返回该工号的所有信息[注意密码],用于确认密码和查询或修改其他信息
sNode* Search_sLink(sLink SL,int id)
{
	sNode* node = SL->head;
	while(node != NULL)
	{
		if(node->id == id) return node;
		else node = node->next;
	}
	return NULL;
}
//放入基本数据
bool Insert_sLink(sLink SL,int id,char password[],char name[],char sex[],char idcard[],char phone[],char state)
{
	//确定插入的数据不会与前面的数据重复,若重复，则将其覆盖
	bool flag = false;//不重复
	sNode* node = SL->head;
	while(node != NULL)
	{
		if(node->id == id) 
		{
			flag = true;//重复了
			break;
		}
		else node = node->next;
	}
	if(flag == false) node = (sNode*)malloc(sizeof(sNode));//未重复

	node->id = id;
	node->state = state;

	strcpy(node->password,password);
	strcpy(node->name,name);
	strcpy(node->sex,sex);
	strcpy(node->idcard,idcard);
	strcpy(node->phone,phone);
	
	if(flag == false)//未重复
	{
		//分数初始化
		node->ChineseScore = -1;
		node->MathScore = -1;
		node->EnglishScore = -1;
		node->TotalScore = -1;
		node->ScoreRank = -1;

		node->prev = NULL;
		node->next = NULL;

		node->prev = SL->tail;
		if(SL->head == NULL) SL->head = node;//从尾部放入
		else SL->tail->next = node;
		SL->tail = node;
	}

	return true;
}
//放入成绩数据,顺便计算三科总分
bool Score_sLink(sLink SL,int id,float ChineseScore,float MathScore,float EnglishScore)
{
	sNode* node = SL->head;
	while(node != NULL)
	{
		if(node->id == id)
		{
			node->ChineseScore = ChineseScore;
			node->MathScore = MathScore;
			node->EnglishScore = EnglishScore;
			float TotalScore = ChineseScore + MathScore + EnglishScore;//三科总分
			node->TotalScore = TotalScore;

			return true;
		}
		else node = node->next;
	}
	return false;//未找到对应id的学生
}
//按总分进行快速排序,顺便计算三科总分排名
bool Sort_sLink(sLink SL,sNode* leftNode,sNode* rightNode,int index)//一开始将index初始化为一,即index = 1;
{	 
	//这个头,尾用来限定范围
	sNode* headNode = leftNode;
	sNode* tailNode = rightNode;

	//test
	//printf("\nhead:%.2lf tail:%.2lf\n",SL->head->TotalScore,SL->tail->TotalScore);
	//printf("\n1:%.2lf 2:%.2lf 3:%.2lf\n",leftNode->prev->TotalScore,leftNode->TotalScore,rightNode->TotalScore);
	//printf("\n197:%.2lf 224:%.2lf\n",rightNode->TotalScore,leftNode->TotalScore);
	//if(rightNode->next == NULL) printf("\n4:\n");

	while(leftNode != rightNode)//排一个数
	{
		while(leftNode != rightNode && leftNode->TotalScore >= rightNode->TotalScore) 
		{
			//test
			//printf("\n左端右移\n");
			
			rightNode = rightNode->prev;
		}
		if(leftNode != rightNode)//交换左右节点
		{
			//交换
			//printf("\n%.2lf <--> %.2lf\n",leftNode->TotalScore,rightNode->TotalScore);

			//先存下左右节点的前后端
			sNode* leftNodeprev = leftNode->prev;
			sNode* leftNodenext = leftNode->next;
			sNode* rightNodeprev = rightNode->prev;
			sNode* rightNodenext = rightNode->next;

			//限定范围
			if(leftNode == headNode) headNode = rightNode;
			if(rightNode == tailNode) tailNode = leftNode;

			//更新头尾节点
			if(leftNode->prev == NULL) SL->head = rightNode;//如果是头,则改变
			if(rightNode->next == NULL) SL->tail = leftNode;//如果是尾,则改变

			//更新交换前后端:两种情况 相邻:false 和 相间:true
			bool flag = true;
			if(leftNode->next == rightNode) flag = false;

			if(flag == true) leftNode->prev = rightNodeprev;
			else leftNode->prev = rightNode;
			if(flag == true) rightNode->next = leftNodenext;
			else rightNode->next = leftNode;

			leftNode->next = rightNodenext;//
			rightNode->prev = leftNodeprev;//

			if(leftNodeprev != NULL) leftNodeprev->next = rightNode;
			if(rightNodenext != NULL) rightNodenext->prev = leftNode;
			if(flag == true) leftNodenext->prev = rightNode;
			if(flag == true) rightNodeprev->next = leftNode;

			//交换左右指针
			sNode* node = leftNode;
			leftNode = rightNode;
			rightNode = node;
		}
		
		/*
		//test
		printf("yq:\n[%.2lf,%.2lf]\n",leftNode->TotalScore,rightNode->TotalScore);
		sNode* tmp = leftNode->next;
		printf("\n%.2lf\n",tmp->TotalScore);

		//test:224
		sNode* mask = Search_sLink(SL,15015230);
		printf("\n%.2lf:224\n",mask->prev->TotalScore);

		//test:197
		sNode* mark = Search_sLink(SL,15015201);
		printf("\n%.2lf:197\n",mark->prev->TotalScore);
		*/

		if(leftNode == rightNode) break;
		else
		{
			leftNode = leftNode->next;
			index++;
		}
		
		//test
		//printf("\nyh:[%.2lf,%.2lf]\n",leftNode->TotalScore,rightNode->TotalScore);

		//test--->两端指针不等-->进入死循环并不是排序的问题
		//if(leftNode == rightNode) printf("\n两端指针相等\n");
		//sleep(5);

		while(leftNode != rightNode && leftNode->TotalScore >= rightNode->TotalScore) 
		{
			//test
			//printf("\n右端左移\n");

			leftNode = leftNode->next;
			index++;
		}
		if(leftNode != rightNode)//交换左右节点
		{
			//交换
			//printf("\n%.2lf <--> %.2lf\n",leftNode->TotalScore,rightNode->TotalScore);
			
			//先存下左右节点的前后端
			sNode* leftNodeprev = leftNode->prev;
			sNode* leftNodenext = leftNode->next;
			sNode* rightNodeprev = rightNode->prev;
			sNode* rightNodenext = rightNode->next;
			
			//限定范围
			if(leftNode == headNode) headNode = rightNode;
			if(rightNode == tailNode) tailNode = leftNode;

			if(leftNode->prev == NULL) SL->head = rightNode;//如果是头,则改变
			if(rightNode->next == NULL) SL->tail = leftNode;//如果是尾,则改变

			//更新交换前后端:两种情况 相邻:false 和 相间:true
			bool flag = true;
			if(leftNode->next == rightNode) flag = false;

			if(flag == true) leftNode->prev = rightNodeprev;
			else leftNode->prev = rightNode;
			if(flag == true) rightNode->next = leftNodenext;
			else rightNode->next = leftNode;

			leftNode->next = rightNodenext;//
			rightNode->prev = leftNodeprev;//

			if(leftNodeprev != NULL) leftNodeprev->next = rightNode;
			if(rightNodenext != NULL) rightNodenext->prev = leftNode;
			if(flag == true) leftNodenext->prev = rightNode;
			if(flag == true) rightNodeprev->next = leftNode;
			
			//交换左右指针
			sNode* node = leftNode;
			leftNode = rightNode;
			rightNode = node;
		}
		//printf("%d %d \n",leftNode->id,rightNode->id);
		
		if(leftNode == rightNode) break;
		else rightNode = rightNode->prev;
		
		//printf("\n[%.2lf,%.2lf] \n",leftNode->TotalScore,rightNode->TotalScore);
	}
	rightNode->ScoreRank = index;//总分排名
	
	//printf("\nTotalScore:%.2lf index:%d \n",rightNode->TotalScore,index);
	//rightNode == leftNode
	if(headNode == rightNode->prev) rightNode->prev->ScoreRank = index-1;
	if(tailNode == rightNode->next) rightNode->next->ScoreRank = index+1;
	if(headNode != rightNode->prev && headNode != rightNode) Sort_sLink(SL,headNode,rightNode->prev,1);
	if(tailNode != rightNode->next && tailNode != rightNode) Sort_sLink(SL,rightNode->next,tailNode,index+1);

	//左右节点
	//printf("\nzuoyoujiedian:[%.2lf,%.2lf]\n",headNode->TotalScore,tailNode->TotalScore);

	return true;
}
//遍历,单科最高分:float CHScore,MHScore,EHScore 单科总分:double CScore,MScore,EScore 单科平均分:float CAScore,MAScore,EAScore 
//sResult Result_sLink(sLink SL)
sResult Result_sLink(sLink SL)
{
	sResult SCR = (sResult)malloc(sizeof(sResult));
	//if(SCR == NULL)
	//{
	//	return NULL;
	//}
	
	//初始化
	SCR->CHScore = 0;
	SCR->MHScore = 0;
	SCR->EHScore = 0;
	SCR->CScore = 0;
	SCR->MScore = 0;
	SCR->EScore = 0;
	SCR->CAScore = 0;
	SCR->MAScore = 0;
	SCR->EAScore = 0;

	sNode* node = SL->head;

	int num = 0;

	
	while(node != NULL)
	{
		num++;
		//单科最高分,[初始化]
		if(node->ChineseScore > SCR->CHScore) SCR->CHScore = node->ChineseScore;
		if(node->MathScore > SCR->MHScore) SCR->MHScore = node->MathScore;
		if(node->EnglishScore > SCR->EHScore) SCR->EHScore = node->EnglishScore;
		//单科总分,[初始化]
		SCR->CScore += node->ChineseScore;
		SCR->MScore += node->MathScore;
		SCR->EScore += node->EnglishScore;

		node = node->next;
	}
	
	
	//单科平均分,[初始化]
	SCR->CAScore = (SCR->CScore / num);
	SCR->MAScore = (SCR->MScore / num);
	SCR->EAScore = (SCR->EScore / num);
	//[注意]:对数据进行类型转换,防止数据过量,造成结构体内存过度------->无效

	//return true;
	return SCR;
}

//初始化链表[已验证]
bool Init_sLink(sLink SL)
{
	//test
	//printf("\nlaoshifaosjfafasd\n");

	sNode* node = SL->head;
	sNode* tmp = node;
	while(node != NULL)
	{
		node = node->next;
		free(tmp);
		tmp = node;
	}
	SL->head = NULL;
	SL->tail = NULL;
}

//遍历,用于[测试]
bool Travel_sLink(sLink SL)
{
	sNode* node = SL->head;
	while(node != NULL)
	{
		printf("%d ",node->id);
		printf("%s ",node->password);
		printf("%s ",node->name);
		printf("%s ",node->sex);
		printf("%s ",node->idcard);
		printf("%s ",node->phone);
		switch(node->state)
		{
			case 0 : printf("在读 ");break;
			case 1 : printf("退学 ");break;
			default : printf("状态未知 ");break;
		}

		printf("%.2lf ",node->ChineseScore);
		printf("%.2lf ",node->MathScore);
		printf("%.2lf ",node->EnglishScore);
		printf("%.2lf ",node->TotalScore);
		printf("%d \n",node->ScoreRank);

		node = node->next;
	}
}

